#pragma once
#include "objectpool.h"

inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
	void* ptr = VirtualAlloc(0, kpage << page_shift, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
	//linux等其他系统下
#endif
	if (ptr == nullptr) throw std::bad_alloc();
	return ptr;
}
inline static void SystemFree(void* ptr)
{
#ifdef _WIN32
	VirtualFree(ptr, 0, MEM_RELEASE);
#else
	// sbrk unmmap等
#endif
}

class Freelist
{
private:
	void** _freelist;//_freelist中的内容是第一个空间的首地址，*_freelist取到的是第一个空间前8/4字节的内容，也就是第二个空间的地址。
	size_t _maxsize = 1;
	size_t _size = 0;
public:
	size_t Size()
	{
		return _size;
	}
	Freelist():
		_freelist(nullptr)
	{}
	void push(void* obj)//头插
	{
		assert(obj);
		*((void**)obj) = _freelist;
		_freelist = (void**)obj;
		_size++;
	}
	void pushrange(void* start, void* end, size_t n)//插入一个区间
	{
		(*(void**)end) = _freelist;
		_freelist = (void**)start;

		//测试验证+条件断点
		void* cur = start;
		int i = 0;
		while (cur)
		{
			i++;
			cur = (*(void**)cur);
		}
		if (i != n)
		{
			int x = 0;
		}

		_size += n;
	}
	void* pop()//头删
	{
		assert(_freelist);
		void** obj = _freelist;
		_freelist = (void**)(*obj);
		_size--;
		return obj;
	}
	bool Empty()
	{
		return _freelist == nullptr;
	}
	size_t& Maxsize()
	{
		return _maxsize;
	}
	void Poprange(void*& start, void*& end)
	{
		assert(_maxsize <= _size);
		start = _freelist;
		end = start;
		for (size_t i = 0; i < _maxsize - 1; i++)
			end = *((void**)end);
		_freelist = (void**)(*(void**)end);
		*((void**)end) = nullptr;
		_size -= _maxsize;
	}
};
	// 整体控制在最多10%左右的内碎片浪费
	// [1,128]					8byte对齐	    freelist[0,16)		16个list
	// [128+1,1024]				16byte对齐	    freelist[16,72)		56个list
	// [1024+1,8*1024]			128byte对齐	    freelist[72,128)	56
	// [8*1024+1,64*1024]		1024byte对齐     freelist[128,184)  56
	// [64*1024+1,256*1024]		8*1024byte对齐   freelist[184,208)  24个

class Sizemodify
{
private:
public:
	static inline size_t roundup(size_t& size, size_t&& alignnum)
	{
		return (size + alignnum - 1) & (~(alignnum-1));
	}
	static inline size_t Roundsize(size_t size)
	{
		if (size <= 128) return roundup(size, 8);
		else if (size <= 1024) return roundup(size, 16);
		else if (size <= 8 * 1024) return roundup(size, 128);
		else if (size <= 64 * 1024) return roundup(size, 1024);
		else if (size <= 256 * 1024) return roundup(size, 8*1024);
		else return roundup(size, 1 << page_shift);//大于256K就按页的大小对齐
	}
	static inline size_t _Index(size_t size,size_t align_shift)
	{
		return ((size + (1 << align_shift) - 1) >> align_shift) - 1;
	}
	static inline size_t Index(size_t size)//计算该大小的内存空间映射的是哪一个自由链表
	{
		assert(size <= max_size);
		int array[4] = { 16,56,56,56 };//每个区间有多少个list
		if (size <= 128) return _Index(size, 3);
		else if (size <= 1024) return _Index(size, 4) + array[0];
		else if (size <= 8 * 1024) return _Index(size, 7) + array[0] + array[1];
		else if (size <= 64 * 1024) return _Index(size, 10) + array[0] + array[1] + array[2];
		else if (size <= 256 * 1024) return _Index(size, 13) + array[0] + array[1] + array[2] + array[3];
		else
		{
			assert(false);
			return -1;
		}
	}
	static size_t sizetonum(size_t size) {
		int num = max_size / size;
		if (num < 2) num = 2;
		else if (num > 512) num = 512;
		return num;
	}
	static size_t sizemovepage(size_t size)
	{
		size_t num = sizetonum(size);
		size_t pages = (num * size) >> page_shift;
		if (pages == 0) pages = 1;
		if (pages > 128) pages = 128;
		return pages;
	}
};

//管理多个连续也的大块内存跨度结构
struct span
{
	Page_ID _pageid = 0;//页号
	size_t _n = 0;//页数
	size_t _objsize = 0;//从页上切下来的小对象的大小

	span* _next = nullptr;//双向指针
	span* _prev = nullptr;

	size_t _usedcount = 0;//被切成小块内存正在被使用的数量
	void* _freelist = nullptr;
	bool _isused = false;  //是否在被使用
};

static objectpool<span> spanpool;

class spanlist//带头双向循环链表
{
private:
	span* _head;
public:
	std::mutex _mtx;//锁
	spanlist()
	{
		_head = spanpool.New();
		_head->_next = _head;
		_head->_prev = _head;
	}
	bool empty()
	{
		return _head == _head->_next;
	}
	void Insert(span* pos, span* newspan)
	{	
		assert(pos);
		assert(newspan);
		span* tmp = pos->_prev;
		tmp->_next = newspan;
		newspan->_next = pos;
		newspan->_prev = tmp;
		pos->_prev = newspan;
	}
	void Erase(span* pos)
	{
		assert(pos);
		assert(pos != _head);
		span* prev = pos->_prev;
		span* next = pos->_next;
		prev->_next = next;
		next->_prev = prev;
	}
	void pushfront(span* s1)
	{
		Insert(begin(), s1);
	}
	span* popfront()
	{
		span* front = _head->_next;
		if (front==nullptr) 
			int x = 0;
		Erase(front);
		return front;
	}
	span* begin()
	{
		return _head->_next;
	}
	span* end()
	{
		return _head;
	}
};

